#ifndef __CORE_TCP_SERVER_H__
#define __CORE_TCP_SERVER_H__

#include "core_server.h"
#include "core_log.h"


CoreCellServer::CoreCellServer(int id)
{
	this->id = id;
	this->maxsockfd = 0;
	this->clients_change = false;
	this->netevent = nullptr;
}

CoreCellServer::~CoreCellServer()
{

}

void CoreCellServer::start()
{
	cthread.start("core_server", nullptr, [this](CoreThread* pthread) {
		this->onRun(pthread);
		});
}

void CoreCellServer::onRun(CoreThread* pthread)
{
	while (pthread->running())
	{
		if (this->clientsBuff.size() > 0)
		{
			std::lock_guard<std::mutex> lock(this->mymutex);
			for (auto client : this->clientsBuff)
			{
				this->clients[client->getsockfd()] = client;
			}
			this->clientsBuff.clear();
			this->clients_change = true;
		}

		if (this->clients.empty())
		{
			std::chrono::milliseconds t(1);
			std::this_thread::sleep_for(t);
			continue;
		}
		fd_set fdRead;
		FD_ZERO(&fdRead);
		if (this->clients_change)
		{
			this->clients_change = false;
			this->maxsockfd = this->clients.begin()->second->getsockfd();
			for (auto iter : this->clients)
			{
				SOCKET curfd = iter.second->getsockfd();
				FD_SET(curfd, &fdRead);
				if (this->maxsockfd < curfd)
				{
					this->maxsockfd = curfd;
				}
			}
			memcpy(&this->fdRead_back, &fdRead, sizeof(fd_set));
		}
		else
		{
			memcpy(&fdRead, &this->fdRead_back, sizeof(fd_set));
		}
		timeval t{ 0,1 };
		int ret = select((int)this->maxsockfd + 1, &fdRead, nullptr, nullptr, &t);
		if (ret < 0)
		{
			CoreLog::getInstance()->info("CoreCellServer::onRun ret=%d",ret);
			pthread->exit();
			break;
		}
		else if (ret == 0)
		{
			//timeout
			continue;
		}
		std::vector<CoreClient*> delclients;
		for (unsigned int n = 0; n < fdRead.fd_count; n++)
		{
			auto iter = this->clients.find(fdRead.fd_array[n]);
			if (iter != this->clients.end())
			{
				int reclen = this->dataReceived(iter->second);
				if (reclen < 0)
				{
					int recerrno = WSAGetLastError();
					CoreLog::getInstance()->info("len=%d errno=%d", reclen, recerrno);
					if (recerrno == WSAEINTR || recerrno == WSAEWOULDBLOCK)
					{
						continue;
					}
					else
					{
						delclients.push_back(iter->second);
					}
				}
				else if (reclen == 0)
				{
					delclients.push_back(iter->second);
				}
			}
		}
		for (auto delclient : delclients)
		{
			this->removeClient(delclient);
		}
	}
}

void CoreCellServer::addClient(int csocketfd)
{
	CoreClient* client = new CoreClient(this->id,csocketfd);
	std::lock_guard<std::mutex> lock(this->mymutex);
	this->clientsBuff.push_back(client);
	if (this->netevent)
	{
		this->netevent->onClientConnectionMade(client);
	}
}

void CoreCellServer::removeClient(CoreClient* pclient)
{
	if (this->netevent)
	{
		this->netevent->onClientConnectionLost(pclient);
	}
	this->clients.erase(pclient->getsockfd());
	delete pclient;
	this->clients_change = true;
}

int CoreCellServer::getClientCount()
{
	return (int)(this->clients.size() + this->clientsBuff.size());
}

void CoreCellServer::setNetEvent(CoreNetEvent* ev)
{
	this->netevent = ev;
}

int CoreCellServer::dataReceived(CoreClient* pclient)
{
	int len = pclient->dataReceived();
	if (this->netevent)
	{
		this->netevent->onDataReceived(pclient);
	}
	while (true)
	{
		int len = pclient->parselen();
		if (len > 0)
		{
			char* data = pclient->getMessage();
			CoreStream* parseStream = new CoreStream(data, len);
			if (this->netevent)
			{
				this->netevent->onPacketReceived(pclient,parseStream);
			}
			delete parseStream;
			pclient->delMessage(len);
		}
		else
		{
			break;
		}
	}
	return len;
}


/*#########################################################################################################*/
CoreServer::CoreServer()
{
	this->sockfd = INVALID_SOCKET;
	this->_recvCount = 0;
	this->_clientCount = 0;
}


CoreServer::~CoreServer()
{
	this->cthread.stop();
	this->closeSocket();
	for (std::vector<CoreCellServer *>::iterator it = cellservers.begin(); it != cellservers.end(); it++)
	{
		delete (*it);
	}
	cellservers.clear();
}

void CoreServer::createSocket()
{
	WORD ver = MAKEWORD(2, 2);
	WSADATA dat;
	WSAStartup(ver, &dat);
	if (this->sockfd != INVALID_SOCKET)
	{
		CoreLog::getInstance()->info("<socket=%d> socket has create,so onClose()", (int)this->sockfd);
	}
	this->sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (this->sockfd == INVALID_SOCKET)
	{
		CoreLog::getInstance()->info("<socket=%d> create socket error", (int)this->sockfd);
	}
	else
	{
		CoreLog::getInstance()->info("<socket=%d> create socket sucess", (int)this->sockfd);
	}
}

void CoreServer::closeSocket()
{
	if (this->sockfd != INVALID_SOCKET)
	{
		::closesocket(this->sockfd);
		WSACleanup();
	}
	this->sockfd = INVALID_SOCKET;
}

int CoreServer::bind(const char* ip, unsigned short port)
{
	if (this->sockfd == INVALID_SOCKET)
	{
		this->createSocket();
	}
	sockaddr_in _sin = {};
	_sin.sin_family = AF_INET;
	if (ip)
	{
		_sin.sin_addr.S_un.S_addr = inet_addr(ip);
	}
	else
	{
		_sin.sin_addr.S_un.S_addr = INADDR_ANY;//inet_addr("127.0.0.1")
											   //_sin.sin_addr.s_addr = htonl(INADDR_ANY);
	}
	_sin.sin_port = htons(port);
	int bindresult = ::bind(this->sockfd, (sockaddr *)&_sin, sizeof(_sin));
	if (bindresult == SOCKET_ERROR)
	{
		CoreLog::getInstance()->info("socket bind<%s:%d> Failed", ip, port);
	}
	else
	{
		CoreLog::getInstance()->info("socket bind<%s:%d> sucess", ip, port);
	}
	return bindresult;
}

int CoreServer::listen(int n)
{
	int listenresult = ::listen(this->sockfd, n);
	if (listenresult == SOCKET_ERROR)
	{
		CoreLog::getInstance()->info("socket=%d listen<%d> failed", (int)this->sockfd, n);
	}
	else
	{
		CoreLog::getInstance()->info("socket=%d listen<%d> sucess", (int)this->sockfd, n);
	}
	return listenresult;
}

void CoreServer::accept()
{
	sockaddr_in clientAddr = {};
	int nAddrLen = sizeof(clientAddr);
	SOCKET _csock = ::accept(this->sockfd, (sockaddr *)&clientAddr, (socklen_t *)&nAddrLen);
	if (_csock == INVALID_SOCKET)
	{
		CoreLog::getInstance()->info("accept error");
	}
	else
	{
		auto minserver = cellservers[0];
		for (auto pcellserver : cellservers)
		{
			if (pcellserver->getClientCount() > minserver->getClientCount())
			{
				minserver = pcellserver;
			}
		}
		minserver->addClient((int)_csock);
	}
}


void CoreServer::start(int threadcount)
{
	for (int i = 0; i < threadcount; i++)
	{
		auto ser = new CoreCellServer(i+1);
		this->cellservers.push_back(ser);
		ser->setNetEvent(this);
		ser->start();
	}

	cthread.start("CoreServerThread", nullptr, [this](CoreThread* pthread) {
		this->onRun(pthread);
	}, [this](CoreThread* pthread) {
		CoreLog::getInstance()->info("CoreServerThread exit");
	});
}

void CoreServer::onRun(CoreThread* pthread)
{
	while (pthread->running())
	{
		fd_set fdRead;
		FD_ZERO(&fdRead);
		FD_SET(this->sockfd, &fdRead);
		timeval t;
		t.tv_sec = 0;
		t.tv_usec = 10;
		int ret = select((int)this->sockfd + 1, &fdRead, NULL, NULL, &t);
		if (ret < 0)
		{
			CoreLog::getInstance()->info("CoreServer::onRun select ret=%d",ret);
			pthread->exit();
			break;
		}
		if (FD_ISSET(this->sockfd, &fdRead))
		{
			FD_CLR(this->sockfd, &fdRead);
			this->accept();
		}
	}
}

void CoreServer::time4msg()
{
	auto t1 = _tTime.getElapsedSecond();
	if (t1 >= 1.0)
	{
		printf("thread<%d>,time<%lf>,socket<%d>,clients<%d>,recvCount<%d>\n", (int)cellservers.size(), t1, (int)this->sockfd, _clientCount, (int)(_recvCount / t1));
		_tTime.update();
		_recvCount = 0;
	}
}


void CoreServer::onClientConnectionMade(CoreClient* pClient)
{
	this->_clientCount++;
}

void CoreServer::onClientConnectionLost(CoreClient* pClient)
{
	this->_clientCount--;
}

void CoreServer::onDataReceived(CoreClient* pClient)
{
	this->_recvCount++;
}

void CoreServer::onPacketReceived(CoreClient* pclient, CoreStream* data)
{
	
}

#endif


